package com.vmj.heap;

import com.vmj.classfile.entity.constantinfo.ConstantFieldRefInfo;

/**
 * Created by yangshoujun on 2017/8/26 下午2:35.
 */
public class FieldRef extends MemberRef {

    private Field field;

    public static FieldRef parseFieldRef(RuntimeConstantPool runtimeConstantPool, ConstantFieldRefInfo refInfo) {

        FieldRef ref = new FieldRef();
        ref.setRuntimeConstantPool(runtimeConstantPool);
        ref.copyMemberRefInfo(refInfo);
        return ref;
    }

    public Field resolvedField() {
        if(this.field == null) {
            resolevedFieldRef();
        }

        return this.field;
    }

    public void resolevedFieldRef() {
        VMClass clazz = this.getRuntimeConstantPool().getClazz();
        VMClass oClazz = this.resolvedClass();

        Field field = lookupField(oClazz, this.getName(), this.getDescriptor());
        if(field == null) {
            throw new RuntimeException("NoSuchFieldError");
        }

        if(!field.isAccessibleTo(clazz)) {
            throw new RuntimeException("java.lang.IllegalAccessException");
        }
        this.field = field;
    }

    public Field lookupField(VMClass clazz, String name, String descriptor) {
        for(Field field : clazz.getFields()) {
            if(field.getName().equals(name) && field.getDescriptor().equals(descriptor)) {
                return field;
            }
        }

        for(VMClass cls : clazz.getInterfaces()) {
            Field field = lookupField(cls, name, descriptor);
            if(field != null) {
                return field;
            }
        }

        if(clazz.getSuperClass() != null) {
            return lookupField(clazz.getSuperClass(), name, descriptor);
        }

        return null;
    }

    public Field getField() {
        return field;
    }

    public void setField(Field field) {
        this.field = field;
    }

    @Override
    public String toString() {
        return field.toString();
    }
}
